Google Search MCP Server

# Comprehensive Model Context Protocol (MCP) Implementation Guide ## Introduction to MCP The Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications - just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools. ### What is MCP? MCP helps you build agents and complex workflows on top of LLMs. LLMs frequently need to integrate with data and tools, and MCP provides: - A standardized way to expose data through Resources - Executable functionality through Tools - Reusable interaction patterns through Prompts - A client-server architecture where a host application can connect to multiple servers ### Core Architecture Components The MCP architecture follows a client-server model with these key components: 1. **Host Applications**: Applications like Claude Desktop, VS Code, or other AI tools that want to access external data and tools 2. **MCP Clients**: Protocol clients that establish and maintain connections with MCP servers, handling capabilities discovery and communication 3. **MCP Servers**: Lightweight programs that expose three types of capabilities: - **Tools**: Functions that can be called by the LLM to perform actions - **Resources**: Data sources that provide context to the LLM - **Prompts**: Reusable templates for LLM interactions 4. **Transport Layer**: Supports two primary mechanisms: - **stdio (stdin/stdout)**: For local communication when clients and servers run on the same machine - **HTTP with Server-Sent Events (SSE)**: For remote communication over networks ## MCP Protocol Details ### Communication Model MCP uses a client-server architecture with JSON-RPC 2.0 as its messaging format. The protocol supports two primary transport mechanisms: 1. **stdio (stdin/stdout)**: Used for local communication when clients and servers run on the same machine 2. **HTTP with Server-Sent Events (SSE)**: Used for remote communication over networks ### Core Capabilities MCP servers can provide three main types of capabilities: 1. **Tools**: Functions that can be called by the LLM (with user approval) to perform actions 2. **Resources**: Data sources that can be read by the LLM (like file contents or API responses) 3. **Prompts**: Reusable templates for LLM interactions ## Server Implementation The server is the component that exposes tools, resources, and prompts to the client. Let's explore implementation approaches in both Python and TypeScript. ### Python Server Implementation Python offers a high-level SDK called `FastMCP` that simplifies server implementation, as well as a lower-level SDK for more advanced use cases. #### Basic Server Setup with FastMCP ```python from fastmcp import FastMCP # Create a named server mcp = FastMCP("MyServer") # Define a tool using decorator syntax @mcp.tool() def add(a: int, b: int) -> int: """Add two numbers together""" return a + b # Define a resource @mcp.resource("example://data") def get_data() -> str: """Provide example data as a resource""" return "Example data content" # Define a prompt @mcp.prompt() def greeting(name: str) -> str: """Return a personalized greeting template""" return f"Hello {name}, how can I help you today?" # Run the server with stdio transport if __name__ == "__main__": mcp.run(transport="stdio") ``` #### Advanced Python Server with Low-Level API ```python import asyncio import mcp.server.stdio import mcp.types as types from mcp.server.lowlevel import NotificationOptions, Server from mcp.server.models import InitializationOptions # Create a server instance server = Server("advanced-server") # Register handlers for protocol requests @server.list_tools() async def handle_list_tools() -> list[types.Tool]: """List available tools""" return [ types.Tool( name="example-tool", description="An example tool", inputSchema={ "type": "object", "properties": { "param1": {"type": "string", "description": "Parameter 1"} }, "required": ["param1"] } ) ] @server.call_tool() async def handle_call_tool(name: str, arguments: dict) -> any: """Handle tool calls""" if name == "example-tool": return f"Executed tool with argument: {arguments['param1']}" raise ValueError(f"Unknown tool: {name}") # Main server execution async def main(): async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): await server.run( read_stream, write_stream, InitializationOptions( server_name="advanced-server", server_version="0.1.0", capabilities=server.get_capabilities( notification_options=NotificationOptions(), experimental_capabilities={}, ), ), ) if __name__ == "__main__": asyncio.run(main()) ``` ### TypeScript Server Implementation TypeScript provides a flexible SDK for MCP server implementation. #### Basic TypeScript Server Setup ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Create a server instance const server = new McpServer({ name: "typescript-server", version: "1.0.0" }); // Define a tool server.setRequestHandler( { jsonrpc: "2.0", method: "tools/list" }, async () => ({ tools: [ { name: "multiply", description: "Multiply two numbers", inputSchema: { type: "object", properties: { a: { type: "number", description: "First number" }, b: { type: "number", description: "Second number" } }, required: ["a", "b"] } } ] }) ); // Handle tool calls server.setRequestHandler( { jsonrpc: "2.0", method: "tools/call" }, async (request) => { const { name, arguments: args } = request.params; if (name === "multiply") { const result = args.a * args.b; return { result }; } throw new Error(`Unknown tool: ${name}`); } ); // Connect to stdio transport and start the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Server running on stdio"); } main().catch((error) => { console.error("Fatal error:", error); process.exit(1); }); ``` ## Client Implementation MCP clients establish connections with servers, discover their capabilities, and relay them to the LLM. Here's how to implement clients in both Python and TypeScript. ### Python Client Implementation #### Basic Python Client ```python import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): # Define server parameters server_params = StdioServerParameters( command="python", # Command to run the server args=["server.py"] # Arguments to pass to the command ) # Connect to the server async with stdio_client(server_params) as (read, write): # Create a client session async with ClientSession(read, write) as session: # Initialize the session await session.initialize() # List available tools tools_response = await session.list_tools() print(f"Available tools: {[tool.name for tool in tools_response.tools]}") # Call a tool result = await session.call_tool("add", {"a": 5, "b": 3}) print(f"5 + 3 = {result.result}") if __name__ == "__main__": asyncio.run(main()) ``` #### Integrating with Claude API ```python import asyncio import os from typing import Optional, List from contextlib import AsyncExitStack from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client from anthropic import Anthropic class MCPClaudeClient: def __init__(self): self.session: Optional[ClientSession] = None self.exit_stack = AsyncExitStack() self.anthropic = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY")) self.tools = [] async def connect_to_server(self, server_script_path): """Connect to an MCP server""" server_params = StdioServerParameters( command="python", args=[server_script_path] ) read, write = await self.exit_stack.enter_async_context(stdio_client(server_params)) self.session = await self.exit_stack.enter_async_context(ClientSession(read, write)) # Initialize session await self.session.initialize() # Discover tools tools_response = await self.session.list_tools() self.tools = tools_response.tools print(f"Connected to MCP server with {len(self.tools)} tools available") async def process_with_claude(self, user_message): """Process user message with Claude using MCP tools""" if not self.session: raise RuntimeError("No active MCP session") # Convert MCP tools to Claude's tool format claude_tools = [] for tool in self.tools: claude_tools.append({ "name": tool.name, "description": tool.description, "input_schema": tool.parameters }) # Send to Claude with tools response = self.anthropic.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=1000, messages=[{"role": "user", "content": user_message}], tools=claude_tools ) # Process Claude's response for content in response.content: if content.type == "tool_use": # Claude wants to use a tool tool_name = content.name tool_args = content.input print(f"Claude is calling tool: {tool_name}") # Call the tool via MCP tool_result = await self.session.call_tool(tool_name, tool_args) # Send the result back to Claude follow_up = self.anthropic.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=1000, messages=[ {"role": "user", "content": user_message}, {"role": "assistant", "content": response.content}, {"role": "tool", "name": tool_name, "content": str(tool_result.result)} ] ) return follow_up return response async def cleanup(self): """Clean up resources""" await self.exit_stack.aclose() async def main(): client = MCPClaudeClient() try: await client.connect_to_server("path/to/server.py") response = await client.process_with_claude("Calculate 5 + 3") print(response) finally: await client.cleanup() if __name__ == "__main__": asyncio.run(main()) ``` ### TypeScript Client Implementation #### Basic TypeScript Client ```typescript import { McpClient } from "@modelcontextprotocol/sdk/client/mcp.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; async function main() { // Create a transport const transport = new StdioClientTransport({ command: "node", args: ["server.js"] }); // Create client and connect const client = new McpClient(); await client.connect(transport); // Create a session const session = await client.createSession(); // Initialize session await session.initialize(); // List available tools const { tools } = await session.listTools(); console.log("Available tools:", tools.map(tool => tool.name)); // Call a tool const result = await session.callTool("multiply", { a: 5, b: 3 }); console.log("5 * 3 =", result.result); // Clean up await client.disconnect(); } main().catch(console.error); ``` ## Python vs TypeScript: A Comparison When choosing between Python and TypeScript for MCP implementation, there are several factors to consider: ### Strengths of Python for MCP 1. **High-Level Abstractions**: Python's `FastMCP` provides a very clean, decorator-based API that makes creating servers intuitive 2. **Type Annotations**: Modern Python's type hints work well with MCP's schema requirements 3. **Async Support**: Python's asyncio integrates well with the asynchronous nature of MCP 4. **AI Ecosystem**: Python has a strong ecosystem for AI/ML, making it easier to integrate with other AI libraries 5. **Claude Integration**: The official Anthropic Python SDK integrates well with MCP ### Strengths of TypeScript for MCP 1. **JSON Native**: TypeScript's JavaScript roots make it natural for working with JSON-RPC 2. **Web Integration**: Better for building web-based clients or servers (especially with SSE transport) 3. **Type System**: More mature type system with interfaces and generics for protocol validation 4. **NPX Execution**: TypeScript servers can be easily run with `npx` without installation 5. **Most Official Examples**: More official example implementations use TypeScript ### Development Experience Comparison | Aspect | Python | TypeScript | |--------|--------|------------| | Setup Complexity | Simpler with FastMCP | More boilerplate code | | Typing Experience | Good, but less strict | Excellent, more strict | | Debugging | Excellent Python tooling | Good browser/Node tooling | | Deployment | Requires Python runtime | Requires Node.js runtime | | Learning Curve | Gentle with FastMCP | Steeper with lower-level API | ### Performance Considerations For most MCP implementations, performance differences between Python and TypeScript will be negligible, as MCP operations are typically I/O bound rather than CPU bound. The choice should be based more on your team's expertise and integration requirements. ## Windows-Specific Considerations Implementing MCP on Windows platforms requires attention to specific issues, especially when using stdio transport: ### Line Ending Handling Windows uses CRLF (`\r\n`) for line endings while Unix systems use LF (`\n`). This can cause issues with stdio transport if not handled correctly. #### Python Solution ```python import sys import os # Force binary mode for stdin/stdout on Windows if sys.platform == 'win32': import msvcrt msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) ``` #### TypeScript Solution ```typescript if (process.platform === 'win32') { process.stdin.setEncoding('binary'); process.stdout.setDefaultEncoding('binary'); } ``` ### Path Separators Windows uses backslashes (`\`) in file paths, while MCP server commands often use forward slashes (`/`). Most MCP SDKs handle this automatically, but custom implementations need to be aware of this difference. ### Executable Extensions Windows commands typically require `.exe` extensions, and JavaScript/TypeScript scripts may require `.cmd` or `.bat` wrappers to run properly. The SDKs handle this, but custom implementations should consider it. ## Best Practices for MCP Implementation ### Security Best Practices 1. **User Consent**: Always obtain explicit user consent before executing tools 2. **Input Validation**: Validate all inputs at both the client and server levels 3. **Least Privilege**: Servers should operate with the minimum required permissions 4. **Secure Protocols**: Use HTTPS for remote connections (SSE transport) 5. **Authentication**: Implement proper authentication for remote servers ### Error Handling 1. **Graceful Degradation**: Handle server unavailability gracefully 2. **Timeouts**: Implement reasonable timeouts for operations 3. **Retry Logic**: Add retry mechanisms for transient failures 4. **Descriptive Errors**: Provide clear error messages for debugging ### Performance Optimization 1. **Connection Pooling**: Reuse connections where possible 2. **Caching**: Cache capabilities and frequently used resources 3. **Batching**: Batch multiple requests when appropriate 4. **Compression**: Use compression for large resource transfers ## Comprehensive Example: Building a Complete MCP Ecosystem Let's put everything together with a complete example that includes: - A Python-based MCP server with multiple tools - A TypeScript-based MCP client - Integration with Claude via the Anthropic API ### Project Structure ``` mcp-ecosystem/ ├── server/ │ ├── server.py # Python MCP server │ └── requirements.txt # Python dependencies ├── client/ │ ├── package.json # Node.js package definition │ ├── tsconfig.json # TypeScript configuration │ └── src/ │ └── client.ts # TypeScript MCP client └── README.md # Project documentation ``` ## Conclusion The Model Context Protocol (MCP) provides a powerful standardized way to integrate LLMs with external tools and data sources. Both Python and TypeScript offer robust SDKs for implementing MCP clients and servers. Python's strengths lie in its simplicity, high-level abstractions, and excellent integration with the AI ecosystem. TypeScript shines with its native JSON handling, strong type system, and web integration capabilities. The choice between Python and TypeScript should be based on your specific requirements, team expertise, and the broader ecosystem you're integrating with. For AI-focused teams already working with Python, the Python SDK offers the smoothest experience. For web developers or teams building web-based AI applications, TypeScript might be the better choice. ## Additional Resources - [Official MCP Documentation](https://modelcontextprotocol.io/docs) - [MCP Specification](https://spec.modelcontextprotocol.io/specification/2025-03-26/) - [TypeScript SDK Repository](https://github.com/modelcontextprotocol/typescript-sdk) - [Python SDK Repository](https://github.com/modelcontextprotocol/python-sdk) - [Example MCP Servers](https://github.com/modelcontextprotocol/servers)
ID: 8m8reyzrcd